<?php

declare(strict_types=1);

namespace NanQi\Hope\Listener;

use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Crontab\CrontabManager;
use Hyperf\Di\Annotation\AnnotationCollector;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Process\Event\BeforeCoroutineHandle;
use Hyperf\Process\Event\BeforeProcessHandle;
use NanQi\Hope\Annotation\Cron;
use NanQi\Hope\Crontab\Crontab;

class CrontabRegisterListener implements ListenerInterface
{
    /**
     * @var \Hyperf\Crontab\CrontabManager
     */
    protected $crontabManager;

    /**
     * @var \Hyperf\Contract\StdoutLoggerInterface
     */
    protected $logger;

    /**
     * @var \Hyperf\Contract\ConfigInterface
     */
    private $config;

    public function __construct(CrontabManager $crontabManager, StdoutLoggerInterface $logger, ConfigInterface $config)
    {
        $this->crontabManager = $crontabManager;
        $this->logger = $logger;
        $this->config = $config;
    }

    public function listen(): array
    {
        return [
            BeforeProcessHandle::class,
            BeforeCoroutineHandle::class,
        ];
    }

    public function process(object $event)
    {
        $crontabs = $this->parseCrontabs();
        foreach ($crontabs as $crontab) {
            if ($crontab instanceof Crontab) {
                $this->logger->debug(sprintf('Crontab %s have been registered.', $crontab->getName()));
                $this->crontabManager->register($crontab);
            }
        }
    }

    private function parseCrontabs(): array
    {
        $annotationCrontabs = AnnotationCollector::getClassesByAnnotation(Cron::class);
        $crontabs = [];
        foreach ($annotationCrontabs as $class => $crontab) {
            if ($crontab instanceof Cron) {
                $crontab = $this->buildCrontabByAnnotation($class, $crontab);
                $crontabs[] = $crontab;
            }
        }
        return $crontabs;
    }

    private function buildCrontabByAnnotation(string $class, Cron $annotation): Crontab
    {
        $crontab = new Crontab();
        $crontab->setName($class);
        $crontab->setRule($annotation->rule)
            ->setCron($class);
        foreach ($annotation->nextList as $next) {
            $crontab->setNextCrontab($next);
        }
        return $crontab;
    }
}
